﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO.MemoryMappedFiles;
using System.IO;
using LogLib;
using System.Drawing;
using ComLib.ComFun;

namespace KProcessor
{
    /// <summary>
    /// 资源接收器（从共享内存中获取照片数据并转化）
    /// </summary>
    public class SourceReceiver
    {
        /// <summary>
        /// 从共享内存获取到的最新照片数据
        /// </summary>
        private byte[] bufferData = null;
        public byte[] NewFrameBuffer
        {
            get { return bufferData; }
        }

        public static long MemoryCapacity = 104857600;

        private const string shareName = "CanonEOS";

        private const string mutexName = "MemoryMapMutex";

        /// <summary>
        /// 错误消息
        /// </summary>
        protected string _error = "";
        public string ErrorMessage
        {
            get { return _error; }
        }

        /// <summary>
        /// 共享文件对象（每次读取内容时最好重新获取）
        /// </summary>
        private MemoryMappedFile mmf = null;

        /// <summary>
        /// 获取进程间同步的对象
        /// </summary>
        private Mutex mutex = null;

        private long nReadDataLength = 0;
        public int ReadDataLength
        {
            get { return (int)nReadDataLength; }
        }

        private static BufferManage _bufferManage;

        static SourceReceiver()
        {
            _bufferManage = BufferManage.Instance;
        }

        public SourceReceiver()
        {

        }

        private bool GetMutex()
        {
            try
            {
                mutex = Mutex.OpenExisting(mutexName);
            }
            catch (Exception ex)
            {
                _error = string.Format("获取同步对象{0}失败, {1}", mutexName, ex.Message);
                Log.WriteExceptionAsync(ex.ToString());
                return false;
            }
            if (!mutex.WaitOne(3000))
            {
                _error = "等待处理共享数据超时。";
                Log.WriteAsync(_error);
                return false;
            }
            return true;
        }

        private bool OpenMappedFile()
        {
            try
            {
                mmf = MemoryMappedFile.OpenExisting(shareName);
                Log.WriteAsync($"打开共享内存映射文件{shareName}成功.");
                return true;
            }
            catch (FileNotFoundException ex)
            {
                _error = "打开共享文件失败:" + ex.Message;
                Log.WriteExceptionAsync(ex.ToString());
                return false;
            }
        }

        private bool GetShareDataLength()
        {
            try
            {
                nReadDataLength = 0;
                using (MemoryMappedViewStream stream = mmf.CreateViewStream(0, 8)) //注意这里的偏移量
                {
                    var reader = new BinaryReader(stream);
                    nReadDataLength = reader.ReadInt64();
                }
                if (nReadDataLength == 0)
                {
                    _error = "获取共享数据长度为0";
                    Log.WriteAsync(_error);
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                _error = "创建共享文件视图(获取照片数据长度)失败:" + ex.Message;
                Log.WriteExceptionAsync(ex.ToString());
                return false;
            }
        }

        private bool ReadShareData()
        {
            try
            {
                using (MemoryMappedViewStream stream = mmf.CreateViewStream(8, 0)) //注意这里的偏移量
                {
                    var reader = new BinaryReader(stream);
                    bufferData = _bufferManage.TakeBuffer((int)nReadDataLength);
                    reader.Read(bufferData, 0, (int)nReadDataLength);
                }
                return true;
            }
            catch (Exception ex)
            {
                _error = "创建共享文件视图(读取照片数据)失败:" + ex.Message;
                Log.WriteExceptionAsync(ex.ToString());
                return false;
            }
        }

        public bool TakePhotoFromShareMemory()
        {
            if (!GetMutex())
            {
                return false;
            }
            bool bRet = false;
            try
            {
                if (OpenMappedFile())
                {
                    if (GetShareDataLength())
                    {
                        if (ReadShareData())
                        {
                            bRet = true;
                        }
                    }
                }
                return bRet;
            }
            catch (Exception ex)
            {
                _error = $"读取共享内存数据发生了异常: {ex.Message}";
                Log.WriteExceptionAsync(ex.ToString());
                return false;
            }
            finally
            {
                mutex.ReleaseMutex();
            }
        }

        public static Bitmap ToBitmap(byte[] Bytes)
        {
            MemoryStream stream = null;
            try
            {
                stream = new MemoryStream(Bytes);
                return new Bitmap(stream);
            }
            catch (ArgumentNullException ex)
            {
                throw ex;
            }
            catch (ArgumentException ex)
            {
                throw ex;
            }
            finally
            {
                stream.Close();
            }
        }

        public bool TakePhotoFromClipboard()
        {
            try
            {
                string filePath = Clipboard.GetText();
                if (File.Exists(filePath))
                {
                    bufferData = _bufferManage.GetFileByteArray(filePath, out nReadDataLength);
                    Log.WriteAsync("从剪切板获取照片数据成功.");
                    return true;
                }
                else
                {
                    Log.WriteAsync("从剪切板获取照片数据失败.");
                    return false;
                }
            }
            catch (Exception ex)
            {
                _error = "从剪切板读取数据失败:" + ex.Message;
                Log.WriteException(ex.ToString());
                return false;
            }
        }
    }
}
